﻿/**************************************************************
* Copyright (C) 2018 www.eipflow.com 孙泽伟版权所有(盗版必究)
*
* 作者: 孙泽伟(QQ 1039318332)
* 创建时间: 2018/10/30 22:40:15
* 文件名: 
* 描述: 
* 
* 修改历史
* 修改人：
* 时间：
* 修改说明：
*
**************************************************************/
using Autofac;
using Autofac.Extensions.DependencyInjection;
using AutoMapper;
using EIP.Common.Controller.Filter;
using EIP.Common.Controller.Middlewares;
using EIP.Common.Controller.Provider;
using EIP.Common.Core.Context;
using EIP.Common.JwtAuthorize;
using EIP.Common.Models.Dtos;
using EIP.Common.Models.Resx;
using EIP.Common.Models.Tree;
using EIP.Common.Util;
using EIP.System.Models.Dtos.Config;
using EIP.System.Models.Dtos.Identity;
using EIP.System.Models.Dtos.Permission;
using EIP.System.Models.Entities;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.PlatformAbstractions;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using NLog;
using NLog.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
namespace EIP.Api
{
    /// <summary>
    /// 
    /// </summary>
    public class Startup
    {
        /// <summary>
        /// 
        /// </summary>
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
            ConfigurationUtil.Configuration = configuration;
        }
        /// <summary>
        /// 
        /// </summary>
        public IConfiguration Configuration { get; }
      
        /// <summary>
        /// 
        /// </summary>
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddSession();//使用Session

            #region 文件上传大小
            //1 GB
            //<requestLimits maxQueryString="302768" maxAllowedContentLength="1073741824" />
            services.Configure<FormOptions>(x =>
            {
                x.ValueLengthLimit = int.MaxValue;
                x.MultipartBodyLengthLimit = int.MaxValue;
                x.MultipartHeadersLengthLimit = int.MaxValue;
            });
            #endregion

            #region 跨域
            services.AddCors(options =>
            {
                options.AddPolicy("EIPCors", policy => policy.WithOrigins(Configuration["Cors:Origins"].Split(',')).AllowAnyHeader().AllowAnyMethod().AllowCredentials());
            });
            #endregion

            #region Swagger基础配置
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc(Configuration["Swagger:Name"], new OpenApiInfo
                {
                    Version = Configuration["Swagger:Version"],
                    Title = Configuration["Swagger:Title"],
                    Description = Configuration["Swagger:Description"],
                });
                var basePath = PlatformServices.Default.Application.ApplicationBasePath;
                c.IncludeXmlComments(Path.Combine(basePath, "EIP.System.Controller.xml"));
                c.IncludeXmlComments(Path.Combine(basePath, "EIP.System.Models.xml"));
                //这里是给Swagger添加验证的部分
                // JWT认证                                                 
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Scheme = "bearer",
                    BearerFormat = "JWT",
                    Type = SecuritySchemeType.Http,
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Description = "Authorization:Bearer 请输入带有Bearer的Token<br/><b></b>",
                });
                c.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme{Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"
                            }
                        },
                        new string[] { }
                    }
                });
            });
            #endregion

            #region jwt
            services.AddApiJwtAuthorize((context) =>
            {
                return ValidatePermission(context);
            });
            #endregion

            #region 注册Mapper
            RegisterMapper();
            #endregion

            #region  EIP基础配置
            services.Configure<EIPConfig>(Configuration.GetSection("EIP"));
            #endregion

            #region Mvc

            services.AddMvc(options =>
                {
                    options.Filters.Add<ExceptionFilter>();
                    options.Filters.Add<ModelStateFilter>();
                    options.Filters.Add<ActionResultFilter>();
                    options.ModelMetadataDetailsProviders.Add(new RequiredBindingMetadataProvider());
                }).AddJsonOptions(options =>
                {

                })
                .AddApplicationPart(Assembly.Load(new AssemblyName("EIP.Authorize.Controller")))
                .AddApplicationPart(Assembly.Load(new AssemblyName("EIP.System.Controller")));

            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddTokenJwtAuthorize();

            services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null).AddNewtonsoftJson(opt =>
            {
                opt.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                //忽略循环引用
                opt.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            });
            #endregion

            #region Autofac注入
            return RegisterAutofac(services);
            #endregion
        }
       
        /// <summary>
        /// Mapper注册
        /// </summary>
        private void RegisterMapper()
        {
            Mapper.Initialize(config =>
            {
                config.CreateMap<SystemDictionary, SystemDictionaryEditOutput>();
                config.CreateMap<SystemDictionary, SystemDictionaryFindOutput>();
                config.CreateMap<SystemUserInfo, SystemUserOutput>();
                config.CreateMap<SystemUserInfo, SystemUserSaveInput>();
                config.CreateMap<SystemUserSaveInput, SystemUserInfo>();
                config.CreateMap<SystemUserOutput, SystemUserDetailOutput>();
                config.CreateMap<SystemMenu, SystemMenuFindOutput>();
                config.CreateMap<SystemMenuButton, SystemMenuButtonOutput>();
                config.CreateMap<SystemOrganization, SystemOrganizationOutput>();
                config.CreateMap<SystemUserInfo, SystemUserFindHeadByIdOutput>();
                config.CreateMap<SystemDistrict, SystemDistrictFindByIdOutput>();
                config.CreateMap<SystemMenu, BaseTree>()
                    .ForMember(o => o.id, opt => opt.MapFrom(src => src.MenuId))
                    .ForMember(o => o.parent, opt => opt.MapFrom(src => src.ParentId))
                    .ForMember(o => o.text, opt => opt.MapFrom(src => src.Name));
                config.CreateMap<SystemDictionary, BaseTree>()
                   .ForMember(o => o.id, opt => opt.MapFrom(src => src.DictionaryId))
                   .ForMember(o => o.parent, opt => opt.MapFrom(src => src.ParentId))
                   .ForMember(o => o.text, opt => opt.MapFrom(src => src.Name));
                config.CreateMap<SystemOrganization, BaseTree>()
                    .ForMember(o => o.id, opt => opt.MapFrom(src => src.OrganizationId))
                    .ForMember(o => o.parent, opt => opt.MapFrom(src => src.ParentId))
                    .ForMember(o => o.text, opt => opt.MapFrom(src => src.Name));

                config.CreateMap<SystemRole, SystemRoleSelectOutput>()
                    .ForMember(o => o.RoleId, opt => opt.MapFrom(src => src.RoleId))
                    .ForMember(o => o.Name, opt => opt.MapFrom(src => src.Name));
            });
        }

        /// <summary>
        /// Autofac配置
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        IServiceProvider RegisterAutofac(IServiceCollection services)
        {
            var builder = new ContainerBuilder();
            builder.Populate(services);
            var assemblys = GetAllAssemblies();
            builder.RegisterAssemblyTypes(assemblys.ToArray()).Where(t => t.Name.EndsWith("Logic")).AsImplementedInterfaces();
            builder.RegisterAssemblyTypes(assemblys.ToArray()).Where(t => t.Name.EndsWith("Repository")).AsImplementedInterfaces();
            return new AutofacServiceProvider(builder.Build());
        }

        /// <summary>
        /// 获取项目程序集
        /// </summary>
        /// <returns></returns>
        static IList<Assembly> GetAllAssemblies()
        {
            var list = new List<Assembly>();
            var deps = DependencyContext.Default;
            var libs = deps.CompileLibraries;
            foreach (var lib in libs)
            {
                try
                {
                    var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name));
                    list.Add(assembly);
                }
                catch (Exception)
                {

                }
            }
            return list;
        }

        /// <summary>
        /// Cusomer Validate Method
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        bool ValidatePermission(HttpContext httpContext)
        {
            var questUrl = httpContext.Request.Path.Value.ToLower();

            //if (permissions != null && permissions.Where(w => w.Url.Contains("}") ? questUrl.Contains(w.Url.Split('{')[0]) : w.Url.ToLower() == questUrl && w.Predicate.ToLower() == httpContext.Request.Method.ToLower()).Count() > 0)
            //{
            //    var roles = httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Role).Value;
            //    var roleArr = roles.Split(',');
            //    var perCount = permissions.Where(w => roleArr.Contains(w.Name)).Count();
            //    if (perCount == 0)
            //    {
            //        httpContext.Response.Headers.Add("error", "no permission");
            //        return false;
            //    }
            //    else
            //    {
            //        return true;
            //    }
            //}
            //else
            //{
            //    return false;
            //}
            return true;
        }
       
        /// <summary>
        /// 
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        /// <param name="loggerFactory"></param>
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            app.UseSession();

            //使用静态上下文
            app.UseStaticHttpContext();

            #region Swagger
            app.UseSwagger();
            app.UseSwaggerUI(options =>
            {
                //options.SwaggerEndpoint("/Api/swagger/" + Configuration["Swagger:Name"] + "/swagger.json", Configuration["Swagger:Description"]);
                options.SwaggerEndpoint("/swagger/" + Configuration["Swagger:Name"] + "/swagger.json", Configuration["Swagger:Description"]);
            });
            #endregion

            #region 错误中间件
            app.UseErrorHandlingMiddleware();
            #endregion

            #region 请求中间件
            app.UseRequestProviderMiddleware();
            #endregion

            #region NLog
            //添加NLog
            //判断当前使用数据库类型
            var connectionType = Configuration.GetSection("EIP:ConnectionType").Value.ToLower();
            switch (connectionType)
            {
                case ResourceDataBaseType.Mysql:
                    LogManager.LoadConfiguration("nlog.mysql.config");
                    break;
                default:
                    LogManager.LoadConfiguration("nlog.config");
                    break;
            }
            loggerFactory.AddNLog();
            LogManager.Configuration.Variables["connectionString"] = Configuration.GetSection("EIP_Log:MasterConnectionString").Value;
            #endregion

            #region 跨域相关
            app.UseCors("EIPCors");
            #endregion

            #region Signalr
            //app.UseSignalR(routes =>
            //{
            //    routes.MapHub<WebSiteHub>("/eiphub");
            //});
            #endregion
            app.Use(next => context =>
            {
                context.Request.EnableBuffering();//启动倒带方式 
                return next(context);
            });
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }

}
